﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Bymed.SpineScan.DataModel;
using Bymed.SpineScan.Service.Shared;
using Bymed.SpineScan.WPF.Model;
using Bymed.SpineScan.WPF.Shared;
using Bymed.SpineScan.WPF.ViewModel.TestItemViewModel;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;

namespace Bymed.SpineScan.WPF.ViewModel
{
    public class TestSummaryViewModel : AllTestItemsAndPatientInfoViewModel
    {
        public const string ShowSingleTestReportMessageToken = "TestSummaryReportShowSingleTestReportMessage";
        public new const string ShowTestSummaryReportMessageToken = "TestSummaryReportShowTestSummaryReportMessage";
        public const string FinishTestMessageToken = "TestSummaryReportFinishTestMessage";

        /// <summary>
        /// Initializes a new instance of the TestSummaryReportViewModel class.
        /// </summary>
        public TestSummaryViewModel(IDataService dataService)
            : base(dataService) { }

        public override void ResetProperties()
        {
            base.ResetProperties();

            SelectAll = false;
            ScoliosisATI.NeedDetailReport = false;
            Kyphosis.NeedDetailReport = false;
            CervicalLateralBending.NeedDetailReport = false;
            ThoracicLateralBending.NeedDetailReport = false;
            LumbarLateralBending.NeedDetailReport = false;
            CervicalFlexExt.NeedDetailReport = false;
            ThoracicFlexExt.NeedDetailReport = false;
            LumbarFlexExt.NeedDetailReport = false;
            CervicalRotation.NeedDetailReport = false;
            ThoracicRotation.NeedDetailReport = false;
            LumbarRotation.NeedDetailReport = false;
            HeadBalance.NeedDetailReport = false;
            ShouldersBalance.NeedDetailReport = false;
            PelvicBalance.NeedDetailReport = false;

            SelectedDiagnosticMessageList.Clear();
            InitializePredefinedDiagnosticMessageList();
        }

        /// <summary>
        /// The <see cref="SelectAll" /> property's name.
        /// </summary>
        public const string SelectAllPropertyName = "SelectAll";

        private bool _selectAll = false;

        /// <summary>
        /// Sets and gets the SelectAll property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public bool SelectAll
        {
            get
            {
                return _selectAll;
            }

            set
            {
                if (_selectAll == value)
                {
                    return;
                }

                RaisePropertyChanging(SelectAllPropertyName);
                _selectAll = value;
                RaisePropertyChanged(SelectAllPropertyName);

                foreach (var item in TestItemList)
                {
                    SetupNeedDetailProperty(item);
                }
            }
        }

        /// <summary>
        /// The <see cref="PredefinedDiagnosticMessageList" /> property's name.
        /// </summary>
        public const string PredefinedDiagnosticMessageListPropertyName = "PredefinedDiagnosticMessageList";

        private ObservableCollection<DiagnosticMessageReference> _predefinedDiagnosticMessageList = new ObservableCollection<DiagnosticMessageReference>();

        /// <summary>
        /// Sets and gets the PredefinedDiagnosticMessageList property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ObservableCollection<DiagnosticMessageReference> PredefinedDiagnosticMessageList
        {
            get
            {
                return _predefinedDiagnosticMessageList;
            }

            set
            {
                if (_predefinedDiagnosticMessageList == value)
                {
                    return;
                }

                RaisePropertyChanging(PredefinedDiagnosticMessageListPropertyName);
                _predefinedDiagnosticMessageList = value;
                RaisePropertyChanged(PredefinedDiagnosticMessageListPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="SelectedDiagnosticMessageList" /> property's name.
        /// </summary>
        public const string SelectedDiagnosticMessageListPropertyName = "SelectedDiagnosticMessageList";

        private ObservableCollection<DiagnosticMessageReference> _selectedDiagnosticMessageList = new ObservableCollection<DiagnosticMessageReference>();

        /// <summary>
        /// Sets and gets the SelectedDiagnosticMessageList property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ObservableCollection<DiagnosticMessageReference> SelectedDiagnosticMessageList
        {
            get
            {
                return _selectedDiagnosticMessageList;
            }

            set
            {
                if (_selectedDiagnosticMessageList == value)
                {
                    return;
                }

                RaisePropertyChanging(SelectedDiagnosticMessageListPropertyName);
                _selectedDiagnosticMessageList = value;
                RaisePropertyChanged(SelectedDiagnosticMessageListPropertyName);
            }
        }

        private RelayCommand<DiagnosticMessageReference> _addDiagnosticMessageCommand;

        /// <summary>
        /// Gets the AddDiagnosticMessage.
        /// </summary>
        public RelayCommand<DiagnosticMessageReference> AddDiagnosticMessageCommand
        {
            get
            {
                return _addDiagnosticMessageCommand ?? (_addDiagnosticMessageCommand = new RelayCommand<DiagnosticMessageReference>(
                    ExecuteAddDiagnosticMessageCommand,
                    CanExecuteAddDiagnosticMessageCommand));
            }
        }

        private void ExecuteAddDiagnosticMessageCommand(DiagnosticMessageReference parameter)
        {
            PredefinedDiagnosticMessageList.Remove(parameter);
            SelectedDiagnosticMessageList.Insert(0, parameter);
        }

        private bool CanExecuteAddDiagnosticMessageCommand(DiagnosticMessageReference parameter)
        {
            return parameter == null ? false : true;
        }

        private RelayCommand<DiagnosticMessageReference> _removeDiagnosticMessageCommand;

        /// <summary>
        /// Gets the RemoveDiagnosticMessageCommand.
        /// </summary>
        public RelayCommand<DiagnosticMessageReference> RemoveDiagnosticMessageCommand
        {
            get
            {
                return _removeDiagnosticMessageCommand ?? (_removeDiagnosticMessageCommand = new RelayCommand<DiagnosticMessageReference>(
                    ExecuteRemoveDiagnosticMessageCommand,
                    CanExecuteRemoveDiagnosticMessageCommand));
            }
        }

        private void ExecuteRemoveDiagnosticMessageCommand(DiagnosticMessageReference parameter)
        {
            SelectedDiagnosticMessageList.Remove(parameter);
            PredefinedDiagnosticMessageList.Insert(0, parameter);
        }

        private bool CanExecuteRemoveDiagnosticMessageCommand(DiagnosticMessageReference parameter)
        {
            return parameter == null ? false : true;
        }

        private RelayCommand _showTestSummaryReportCommand;

        /// <summary>
        /// Gets the ShowTestSummaryReportCommand.
        /// </summary>
        public new RelayCommand ShowTestSummaryReportCommand
        {
            get
            {
                return _showTestSummaryReportCommand ?? (_showTestSummaryReportCommand = new RelayCommand(
                    ExecuteShowTestSummaryReportCommand,
                    CanExecuteShowTestSummaryReportCommand));
            }
        }

        private void ExecuteShowTestSummaryReportCommand()
        {
            // Send to TestSummaryPage to show test summary result report.
            ViewModelHelper.SyncTestItemListToProperties(this);
            Messenger.Default.Send<TestSummaryViewModel>(this, ShowTestSummaryReportMessageToken);
        }

        private bool CanExecuteShowTestSummaryReportCommand()
        {
            return TestItemList.Any(p => p.NeedDetailReport);
        }

        private RelayCommand _finishCommand;

        /// <summary>
        /// Gets the FinishCommand.
        /// </summary>
        public RelayCommand FinishCommand
        {
            get
            {
                return _finishCommand
                    ?? (_finishCommand = new RelayCommand(
                                          () =>
                                          {
                                              try
                                              {
                                                  SaveTestTracking();

                                                  // Send GoToNextPageMessage to TestSummaryPage.
                                                  Messenger.Default.Send<TestSummaryViewModel>(this, FinishTestMessageToken);
                                              }
                                              catch (Exception ex)
                                              {
                                                  RequestDisplayErrorMessage(ex.Message);
                                              }
                                          }));
            }
        }

        /// <summary>
        /// Add all current test results into data source.
        /// </summary>
        private void SaveTestTracking()
        {
            // Create new TestTracking data.
            var testTracking = new TestTracking
            {
                TestTimestamp = GeneralUtility.GetTimestamp(),
                PatientNumber = PatientBasicInfoDisplayViewModel.Number,
                AttendingDoctorName = AttendingDoctor == null ? string.Empty : AttendingDoctor.Name,
                AttachedDiagnosticMessage = AttachedDiagnosticMessage.Trim(),
                TestDate = GeneralUtility.GetCurrentDateTime()
            };

            // Add all TestResults.
            foreach (var item in TestItemList)
            {
                testTracking.TestResults.Add(new TestResult
                {
                    TestTimestamp = testTracking.TestTimestamp,
                    TestItemName = item.TestItemName,
                    ResultRawData = item.ResultRawData,
                    Graph = ConvertGraphData(item.GraphData)
                });
            }

            // Add selected diagnostic message.
            foreach (var diagnosticMessage in SelectedDiagnosticMessageList)
            {
                testTracking.TestResultDiagnosticMessages.Add(new TestResultDiagnosticMessage
                    {
                        TestTimestamp = testTracking.TestTimestamp,
                        MessageContent = diagnosticMessage.MessageContent
                    });
            }

            ServiceFactory.CreateTestTrackingService().Add(testTracking);
        }

        /// <summary>
        /// Convert ObservableCollection<KeyValuePair<int, double>> to formatted string.
        /// </summary>
        /// <param name="graphData">ObservableCollection<KeyValuePair<int, double>> contains all graph data.</param>
        /// <returns>Formatted string result. Every graph data is separated by pile (|).</returns>
        private string ConvertGraphData(IList<KeyValuePair<int, double>> graphData)
        {
            if (graphData.Count > 0)
            {
                var convertedResult = new StringBuilder();

                for (int i = 0; i < graphData.Count; i++)
                {
                    if (i == graphData.Count - 1)
                    {
                        convertedResult.AppendFormat("{0}", graphData[i].Value);
                    }
                    else
                    {
                        convertedResult.AppendFormat("{0}|", graphData[i].Value);
                    }
                }

                return convertedResult.ToString();
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Setup the NeedDetail property for the provided SingleTestItemViewModel based on select all property.
        /// </summary>
        /// <param name="testItem"></param>
        private void SetupNeedDetailProperty(SingleTestItemViewModel testItem)
        {
            testItem.NeedDetailReport = testItem.IsSelected ? _selectAll : false;
        }

        /// <summary>
        /// Load the data from data source for initializing PredefinedDiagnosticMessageList. 
        /// </summary>
        private void InitializePredefinedDiagnosticMessageList()
        {
            var diagnosticMessageReferenceList = ServiceFactory.CreateDiagnosticMessageReferenceService().GetAll().OrderBy(m => m.OrderIndex);
            PredefinedDiagnosticMessageList = new ObservableCollection<DiagnosticMessageReference>(diagnosticMessageReferenceList);
        }
    }
}
